const { v4 } = require("uuid");
const db = require("@/db/mysql");
const AppConfig = require("$config/app.config");
const dateUtil = require("@/utils/date.util");
const { TenantContext } = require("@/core/tenant-context");

/**
 * 公共模型
 */
class PublicModel {
	/**
	 * sql查询
	 * @param {*} sql
	 * @returns
	 */
	query(sql) {
		return db.query(sql);
	}

	/**
	 * 创建语句
	 * @param {*} param0
	 */
	async create({ table, data, result, isNotTenant }) {
        let [error, _data] = [null, null];
		try {
            const rowId = data.id ? String(data.id).toUpperCase() : v4().toUpperCase();
			data = {
				...data,
				// 主键
				id: rowId,
				// 租户
				tenant_id: data.tenant_id || TenantContext.getCurrentTenant(),
				// 创建人
				created_by: data.created_by || TenantContext.getCurrentUser(),
				// 创建时间
				created_at: data.created_at || dateUtil.formatDate(Date.now(), "yyyy-MM-dd hh:mm:ss")
			};
            // 如果不需要租户
            if (isNotTenant) {
                delete data.tenant_id;
            }

			const fields = [];
			const placeholders = [];
			const values = [];
			for (const [key, value] of Object.entries(data)) {
				fields.push(key);
				placeholders.push("?");
				values.push(value === undefined ? null : value);
			}
            const valuesString = values.reduce((res, v, i) => {
               const item = (typeof v === "string" ? `'${v}'` : v)
                res += i === 0 ? item : `, ${item}`;
                return res;
            }, '')
			const SQL = `INSERT INTO ${table} (${fields.join(", ")}) VALUES (${valuesString})`;
			const queryResult = await this.query(SQL, values);
			if (queryResult.code === 200) {
				// 是否需要返回结果
				if (result) {
					const [error, _d] = await this.findById({ table, id: data.id, isNotTenant });
					if (error) {
						return [error, null];
					}
					_data = _d;
				}
				return [null, _data];
			}
			return ["创建失败", _data];
		} catch (error) {
			console.log(`[${table}] 创建数据失败：error`, error);
			return [error.message, null];
		}
	}

	/**
	 * 创建多条记录
	 * @param {*} param0
	 */
	async createMultiple({ table, data, result, isNotTenant }) {
		try {
			const values = [];
			const ids = [];
			const businessFields = Object.keys(data[0]);
			const tableFields = ["id", "tenant_id", ...Object.keys(data[0]), "created_by", "created_at"];
            // 不需要租户
            if (isNotTenant) {
                tableFields.splice(1, 1);
            }

			data.forEach(row => {
				const id = v4();
				// 主键、租户id
				const rowData = isNotTenant ? [`${id}`] : [`${id}`, `${TenantContext.getCurrentTenant()}`];
				// 字段数据
				businessFields.forEach(col => {
					rowData.push(typeof row[col] === 'undefined' ? null : row[col]);
				});
				// 创建人、时间
				rowData.push(`${TenantContext.getCurrentUser()}`, `${this.time}`);
                const valuesString = rowData.reduce((res, v, i) => {
                    const item = (typeof v === "string" ? `'${v}'` : v)
                    res += i === 0 ? item : `, ${item}`;
                    return res;
                }, '')
				values.push(`(${valuesString})`);
				ids.push(id);
			});
			const SQL = `INSERT INTO ${table} (${tableFields.join(", ")}) VALUES ${values.join(", ")}`;
			const insertResult = await this.query(SQL);
			if (insertResult.code === 200) {
                // 是否需要返回查询结果
                if (result) {
                    const [error, _findResult] = await this.findById({ table: table, id: ids, isNotTenant: isNotTenant });
                    if (error) {
                        return ["创建多条记录查询失败", null];
                    }
                    return [null, _findResult];
                }
				return [null, true];
			}
			return ["多条记录创建失败", null];
		} catch (error) {
			console.log("PublicModel.createMultiple错误：", error);
			return ["多条记录创建失败", null];
		}
	}

	/**
	 * 删除
	 * @param {*} param0
	 */
	async deleteById({ table, id }) {
		try {
			const SQL = this.whereAnd(`UPDATE ${table} SET is_delete = 1`, {
				id: id,
				is_lock: 0,
				tenant_id: TenantContext.getCurrentTenant()
			});
			const result = await this.query(SQL);
			if (result.code === 200 && result.results.changedRows > 0) {
				return [null, 0];
			}
			return ["删除失败", 0];
		} catch (error) {
			console.log(`publicModel.deleteById: [${table}], id=${id}失败`, error);
			return [error.message, null];
		}
	}

	/**
	 * 修改语句
	 * @param {*} param0
	 */
	async updateById({ table, data, id, tid, uid,  result }) {
        let [error, _data] = [null, null];
		try {
            tid = tid || TenantContext.getCurrentTenant();
            uid = uid || TenantContext.getCurrentTenant();
			const disableUpdateFields = ["id", "tenant_id", "is_delete", "is_lock", "created_by", "created_at"]; // 禁止修改的字段
			// 过滤出修改字段
			const updateFields = Object.keys(data).filter(key => {
				if (disableUpdateFields.includes(key)) return false;
				return typeof data[key] !== "undefined";
			});
			// 修改的新值
			const newValueString = updateFields
				.map(key => {
					const value = `${typeof data[key] === "string" ? "'" + data[key] + "'" : data[key]}`;
					return `${key} = ${value}`;
				})
				.join(", ");
			const SQL = `UPDATE ${table} SET ${newValueString}, ${this.injectUpdateFields({
				uid
			})} WHERE is_delete = 0 AND id = '${id}' AND tenant_id = '${tid}'`;
			const queryResult = await this.query(SQL);
			// 编辑成功
			if (queryResult.code === 200 && queryResult.results.changedRows > 0) {
				// 是否需要返回结果
				if (result) {
					const [err, d] = await this.findById({ table, id: id });
					if (err) {
						return [err, null];
					}
					_data = d;
				}
				return [null, _data];
			}
			return ["修改失败", _data];
		} catch (error) {
			console.log(`[${table}] 修改数据失败：error`, error);
			return [error.message, null];
		}
	}

	/**
	 * 通过id查询数据
	 * @param {*} param0
	 * @returns
	 */
	async findById({ table, id, isNotTenant }) {
		try {
			const _id = typeof id === "string" ? [id] : id;
			const idCond = _id.map(i => `'${i}'`).join(", ");
			const SQL = isNotTenant ? `SELECT * FROM ${table} WHERE id IN (${idCond}) AND is_delete = 0` : this.injectTenantCondition(`SELECT * FROM ${table} WHERE id IN (${idCond}) AND is_delete = 0`);
			const results = await this.query(SQL, id);
			if (results.code === 200 && results.results.length > 0) {
				const result = typeof id === "string" ? results.results[0] : results.results;
				return [null, result];
			}
			return ["查询失败", null];
		} catch (error) {
			console.log("findById查询失败：", error);
			return ["查询失败", null];
		}
	}

	sql(sql) {
		return sql.replace(/\s+/g, " ");
	}

	/**
	 * where条件
	 * @param {*} sql
	 * @param {*} data
	 * @returns
	 */
	whereAnd(sql, data) {
		if (!sql) return sql;
		const conditions = Object.keys(data)
			.map(key => {
				const value = typeof data[key] === "string" ? `'${data[key]}'` : data[key];
				return `${key} = ${value}`;
			})
			.join(" AND ");
		// 如果窜在条件
		if (sql.toUpperCase().includes(" WHERE ")) {
			return sql.replace(" WHERE ", `${conditions} AND `);
		}
		// 不存在直接拼接
		return `${sql} WHERE ${conditions}`;
	}

	/**
	 * and条件
	 * @param {*} key
	 * @param {*} value
	 * @param {*} isString
	 * @returns
	 */
	and(key, value, isString) {
		if (typeof value === undefined) {
			return "";
		}
		if (isString && String(value).length === 0) {
			return "";
		}
		// 如果为数字，并且传入的值为如下
		if (!isString && ["", null, undefined].includes(value)) {
			return "";
		}

		return ` AND ${key} = ${isString ? "'" + value + "'" : value}`;
	}

	/**
	 * UUID
	 * @returns
	 */
	get id() {
		return v4();
	}

	/**
	 * 当前日期
	 * @returns
	 */
	get time() {
		const now = new Date();
		const date = [now.getFullYear(), now.getMonth() + 1, now.getDate()].map(i => (i < 10 ? "0" + i : i)).join("-");
		const time = [now.getHours(), now.getMinutes(), now.getSeconds()].map(i => (i < 10 ? "0" + i : i)).join(":");
		return `${date} ${time}`;
	}

	/**
	 * 分页
	 * @param {*} pageSize
	 * @param {*} pageIndex
	 * @returns
	 */
	pageLimit(pageSize, pageIndex) {
		pageSize = Number(pageSize) || AppConfig.PAGE_DEFAULT_SIZE;
		pageSize = pageSize > AppConfig.PAGE_MAX_SIZE ? AppConfig.PAGE_MAX_SIZE : pageSize;
		pageIndex = Number(pageIndex) || 1;
		if (pageIndex === 1) {
			return `${0}, ${pageSize}`;
		}
		return `${pageIndex * pageSize - pageSize}, ${pageSize}`;
	}

	/**
	 * id拼接
	 * @param {*} ids
	 * @returns
	 */
	idJoin(ids) {
		if (typeof ids === "string") return `'${ids}'`;
		return ids.map(i => "'" + i + "'").join(", ");
	}

	/**
	 * 在原始SQL中自动注入租户条件
	 * @param {*} sql
	 * @returns
	 */
	injectTenantCondition(sql) {
		const _sql = sql.toUpperCase();
		const tenantId = TenantContext.getCurrentTenant(); // 当前租户id
		// 简单实现 - 实际应根据SQL解析器处理
		if (sql.toUpperCase().includes("WHERE")) {
			return sql.replace("WHERE", ` WHERE tenant_id = '${tenantId}' AND `);
		} else if (sql.includes("where")) {
			return sql.replace("where", ` where tenant_id = '${tenantId}' and `);
		} else {
			return `${sql} WHERE tenant_id = '${tenantId}'`;
		}
	}

	/**
	 * 在原始语句上添加创建字段
	 * @param {*} uid
	 * @returns
	 */
	injectCreateFields({ uid } = {}) {
		return ` created_by = '${uid || TenantContext.getCurrentUser()}', created_at = '${dateUtil.formatDate(
			Date.now(),
			"yyyy-MM-dd hh:mm:ss"
		)}'`;
	}

	/**
	 * 在原始语句上添加update SQL
	 * @param {*} uid
	 * @returns
	 */
	injectUpdateFields({ uid } = {}) {
		return ` updated_by = '${uid || TenantContext.getCurrentUser()}', updated_at = '${dateUtil.formatDate(
			Date.now(),
			"yyyy-MM-dd hh:mm:ss"
		)}'`;
	}
}

module.exports = PublicModel;
